package com.zqs.compareface.server.camstream;

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.IplImage;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Point;
import org.bytedeco.opencv.opencv_core.Scalar;

import javax.swing.*;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @program: FaceCompare
 * @description:
 * @author: ZQS
 * @create: 2021-08-08 16:54
 */
public class CamStreamPush {
    /**
     * 开启本地摄像头并推流，无监视器
     * @throws FrameGrabber.Exception
     */
    public void openCamAndPushWithoutMonitor(String outputFile) throws FrameGrabber.Exception, FrameRecorder.Exception, InterruptedException {
        //如果有多个摄像头请改这个。0表示第一个
        OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
        //360p 480x360 或 480p 640x480
        grabber.setImageWidth(640);
        grabber.setImageHeight(480);
        //开始获取摄像头数据
        try{
            grabber.start();
        }catch (Exception e){
            try {
                //一次重启尝试
                grabber.start();
            }catch (Exception e2){
                throw e;
            }
        }
        /**
         * local抽帧
         */
        OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();//转换器
        IplImage grabbedImage = converter.convert(grabber.grab());//抓取一帧视频并将其转换为图像，将这一帧转换为IplImage

        /**
         * 开一个窗口查看视频画面，根据需要开启
         */
/*        CanvasFrame frame = new CanvasFrame("camera");//新建一个窗口
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setAlwaysOnTop(true);*/

        /**
         * 开始推流或录制保存，具体根据outpufile的地址来
         */
        int width = grabbedImage.width();
        int height = grabbedImage.height();
        FrameRecorder recorder = FrameRecorder.createDefault(outputFile, width, height);
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_FLV1);
        recorder.setFormat("flv");//封装格式，如果是推送到rtmp就必须是flv封装格式
        recorder.setFrameRate(30.0);
        recorder.setVideoBitrate(800000);
        try{
            recorder.start();//开启录制器
        }catch (Exception e){
            try {
                recorder.start();//如果失败了再次尝试开启
            }catch (Exception e2){
                throw  e;
            }
        }

        /**
         * 抓取本地视频流后进行推流
         */
        // 水印文字位置
        Point point = new Point(50, 30);
        // 颜色，使用黄色
        Scalar scalar = new Scalar(0, 255, 255, 0);
        Date nowTime = new Date(System.currentTimeMillis());
        SimpleDateFormat sdFormatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        long startTime = 0;
        long videoTS = 0;
        long time = System.currentTimeMillis();
        Mat mat = null;
        /**
         * //如果不能推到rtmp 这里就取消注释进行第一次转换，可能是选择了h264编码的原因
         * 选择AV_CODEC_ID_FLV1 能正常使用
         * 推流用的是FLV格式，所以避免再转一次码
         */

        while ((grabbedImage = converter.convert(grabber.grab())) != null) {
            String now = sdFormatter.format(System.currentTimeMillis());
            Frame rotatedFrame = converter.convert(grabbedImage);

            // 取一帧视频（图像），并转换为Mat
            mat = converter.convertToMat(rotatedFrame);
            // 加文字水印，opencv_imgproc.putText（图片，水印文字，文字位置，字体，字体大小，字体颜色
            opencv_imgproc.putText(mat, now, point, opencv_imgproc.INTER_LINEAR, 1.2, scalar);
/*            frame.showImage(converter.convert(mat));*/
            if (startTime == 0) {
                startTime = System.currentTimeMillis();
            }
            videoTS = 1000 * (System.currentTimeMillis() - startTime);
            recorder.setTimestamp(videoTS);
            //和帧率相关，不设置则是全帧率
            recorder.record(rotatedFrame);
            //XX毫秒刷新一次图像
            Thread.sleep(50);
        }
        mat.release();
        mat.close();
//        frame.dispose();//关闭窗口
        recorder.close();//关闭推流录制器，close包含release和stop操作
        grabber.close();//关闭抓取器
    }

    /**
     * 开始推流，有监视器
     * @param outputFile
     * @throws FrameRecorder.Exception
     * @throws FrameGrabber.Exception
     */
    public void openCamAndPushWithMonitor(String outputFile) throws FrameRecorder.Exception, FrameGrabber.Exception {
        //如果有多个摄像头请改这个。0表示第一个
        OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
        //360p 480x360 或 480p 640x480
        grabber.setImageWidth(640);
        grabber.setImageHeight(468);

        //开始获取摄像头数据
        try{
            grabber.start();
        }catch (Exception e){
            try {
                //一次重启尝试
                grabber.start();
            }catch (Exception e2){
                throw e;
            }
        }
        /**
         * local抽帧
         */
        OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();//转换器
        IplImage grabbedImage = converter.convert(grabber.grab());//抓取一帧视频并将其转换为图像，将这一帧转换为IplImage


        /**
         * 开一个窗口查看视频画面，根据需要开启
         */
        CanvasFrame frame = new CanvasFrame("camera");//新建一个窗口
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setAlwaysOnTop(true);

        /**
         * 开始推流或录制保存，具体根据outpufile的地址来
         */
        int width = grabbedImage.width();
        int height = grabbedImage.height();
        FrameRecorder recorder = FrameRecorder.createDefault(outputFile, width, height);
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_FLV1);
        recorder.setFormat("flv");//封装格式，如果是推送到rtmp就必须是flv封装格式
        recorder.setFrameRate(30.0);
        recorder.setVideoBitrate(800000);
        try{
            recorder.start();//开启录制器
        }catch (Exception e){
            try {
                recorder.start();//如果失败了再次尝试开启
            }catch (Exception e2){
                throw  e;
            }
        }

        /**
         * 抓取本地视频流后进行推流
         */
        // 水印文字位置
        Point point = new Point(50, 30);
        // 颜色，使用黄色
        Scalar scalar = new Scalar(0, 255, 255, 0);
        Date nowTime = new Date(System.currentTimeMillis());
        SimpleDateFormat sdFormatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        long startTime = 0;
        long videoTS = 0;
        long time = System.currentTimeMillis();
        Mat mat = null;
        /**
         * //如果不能推到rtmp 这里就取消注释进行第一次转换，可能是选择了h264编码的原因
         * 选择AV_CODEC_ID_FLV1 能正常使用
         * 推流用的是FLV格式，所以避免再转一次码
         */
//        Frame rotatedFrame = converter.convert(grabbedImage);
        while ((grabbedImage = converter.convert(grabber.grab())) != null) {
            String now = sdFormatter.format(System.currentTimeMillis());
            Frame rotatedFrame = converter.convert(grabbedImage);

            // 取一帧视频（图像），并转换为Mat
            mat = converter.convertToMat(rotatedFrame);
            // 加文字水印，opencv_imgproc.putText（图片，水印文字，文字位置，字体，字体大小，字体颜色
            opencv_imgproc.putText(mat, now, point, opencv_imgproc.INTER_LINEAR, 1.2, scalar);

            frame.showImage(converter.convert(mat));

            if (startTime == 0) {
                startTime = System.currentTimeMillis();
            }
            videoTS = 1000 * (System.currentTimeMillis() - startTime);
            recorder.setTimestamp(videoTS);
            //和帧率相关，不设置则是全帧率
            recorder.record(rotatedFrame);
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
        mat.release();
        mat.close();
        frame.dispose();//关闭窗口
        recorder.close();//关闭推流录制器，close包含release和stop操作
        grabber.close();//关闭抓取器
    }
}
